﻿using System;
using ibuddylib;

namespace Com.Enterprisecoding.TFS.CheckInNotifier {
    internal class BuddyDancePattern {
        private static int[] PATTERN_REPEATS = new[] { 2, 4, 6, 8 };
        private static HeadColor[] ALL_COLORS = new[] {
            HeadColor.Cyan, HeadColor.Blue, HeadColor.Green, HeadColor.White,
            HeadColor.Yellow, HeadColor.Off, HeadColor.Purple, HeadColor.Red
        };

        // Probably matrix for a 4ths-based measure
        private static double[] PROBS_4 = new[] { 0.8, 0.1, 0.4, 0.1, 0.4, 0.1, 0.4, 0.1, 0.7, 0.1, 0.4, 0.1, 0.4, 0.1, 0.4, 0.1 };

        private static double[] PROBS_3 = new[] { 0.8, 0.2, 0.5, 0.2, 0.5, 0.2, 0.6, 0.2, 0.5, 0.2, 0.5, 0.2 };

        private static Random random = new Random();
        private int repeats;
        private int steps;
        private int position;

        private bool[] beats;
        private bool[] flaps;
        private bool[] twists;
        private bool[] blinks;
        private HeadColor[] colors;

        internal BuddyDancePattern(int measure_length)
        {
            steps   = measure_length * 2;
            repeats = pick<int>(PATTERN_REPEATS);

            double[] ref_matrix = measure_length == 3 || measure_length == 6 ? PROBS_3 : PROBS_4;

            beats  = patternize(steps, ref_matrix);
            flaps  = patternize(steps, ref_matrix);
            twists = patternize(steps, ref_matrix);
            blinks = patternize(steps, ref_matrix);
            colors = pickN<HeadColor>(ALL_COLORS, steps);

            position = 0;
        }

        private T pick<T>(T[] from) {
            return from[random.Next(0, from.Length - 1)];
        }

        private T[] pickN<T>(T[] from, int n) {
            T[] ret = new T[n];
            for (int i = 0; i < n; i++)
                ret[i] = pick<T>(from);
            return ret;
        }

        private bool[] patternize(int length, double[] probs) {
            bool[] ret = new bool[length];

            for (int i = 0; i < length; i++)
                ret[i] = random.NextDouble() <= probs[i];

            return ret;
        }

        internal void step(BuddyAnimator animator) {
            if (beats[position]) animator.HeartBeat();
            if (flaps[position]) animator.Flap();
            if (twists[position]) animator.Twist();
            if (blinks[position]) animator.FlashColor(colors[position]);

            position++;
            if (position == steps) {
                position = 0;
                repeats--;
            }
        }

        internal bool Exhausted {
            get {
                return repeats <= 0;
            }
        }
    }
}
